﻿using System;
using System.Collections.Generic;
using System.IO.Ports;
using System.Text;
using System.Windows.Forms;

namespace _3_串口助手
{
    public partial class FrmMain : Form
    {
        /// <summary>
        /// 声明打开串口按钮文本控制变量
        /// </summary>
        private bool isOpen = false;

        /// <summary>
        /// 声明是否接收数据变量
        /// </summary>
        private bool isRxShow = true;

        /// <summary>
        /// 声明接收数据的缓存区
        /// </summary>
        private readonly List<byte> receiveBuffer = new List<byte>();

        /// <summary>
        /// 声明发送数据的缓存区
        /// </summary>
        private readonly List<byte> sendBuffer = new List<byte>();

        /// <summary>
        /// 声明接收数据的计数器
        /// </summary>
        private int receiveCount = 0;

        /// <summary>
        /// 声明发送数据的计时器
        /// </summary>
        private int sendCount = 0;

        #region 构造函数
        /// <summary>
        /// 构造函数
        /// </summary>
        public FrmMain()
        {
            InitializeComponent();
            CheckForIllegalCrossThreadCalls = false;        //是否对捕获到错误的线程调用
        } 
        #endregion

        #region 程序加载事件
        /// <summary>
        /// 程序加载事件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void FrmMain_Load(object sender, EventArgs e)
        {
            //初始化端口
            InitialSetting();
        }
        #endregion

        #region 端口配置方法
        /// <summary>
        /// 端口配置方法
        /// </summary>
        private void InitialSetting()
        {
            //获取通信端口
            string[] ports = SerialPort.GetPortNames();
            if (ports.Length > 0)
            {
                Port_cob.DataSource = ports;
                //Port_cob.SelectedIndex = 0;

                //波特率
                string[] bauds = new string[] { "4800", "9600", "19200", "38400" };
                Baud_cob.DataSource = bauds;
                Baud_cob.SelectedIndex = 1;
                //校验位
                Parity_cob.DataSource = Enum.GetNames(typeof(Parity));
                //数据位
                int[] datas = new int[] { 5, 6, 7, 8 };
                DataBit_cob.DataSource = datas;
                DataBit_cob.SelectedIndex = 3;
                //停止位
                StopBit_cob.DataSource = Enum.GetNames(typeof(StopBits));
                StopBit_cob.SelectedIndex = 1;
            }
            else
            {
                State_tssl.Text = "本地没有串口！";
            }
        }
        #endregion

        #region 打开串口按钮事件
        /// <summary>
        /// 打开串口按钮事件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Open_btn_Click(object sender, EventArgs e)
        {
            try
            {
                if (!Rs232.IsOpen)
                {
                    Rs232.PortName = Port_cob.Text.Trim();                                                  //端口号
                    Rs232.BaudRate = Convert.ToInt32(Baud_cob.Text.Trim());                                 //比特率
                    Rs232.DataBits = Convert.ToInt32(DataBit_cob.Text.Trim());                              //数据位
                    Rs232.Parity = (Parity)Enum.Parse(typeof(Parity), Parity_cob.Text.Trim());              //校验位
                    Rs232.StopBits = (StopBits)Enum.Parse(typeof(StopBits), StopBit_cob.Text.Trim());       //停止位
                    Rs232.RtsEnable = RTS_chb.Checked;                                                      //RTS
                    Rs232.DtrEnable = DTR_chb.Checked;                                                      //DTR
                    Rs232.Open();                                                                           //打开串口
                    isOpen = true;
                    State_tssl.Text = Port_cob.Text + "端口已打开";
                    Open_btn.Text = "关闭串口";

                    #region 不启用控件
                    Port_cob.Enabled = false;
                    Baud_cob.Enabled = false;
                    Parity_cob.Enabled = false;
                    DataBit_cob.Enabled = false;
                    StopBit_cob.Enabled = false;
                    RTS_chb.Enabled = false;
                    DTR_chb.Enabled = false;
                    #endregion
                }
                else
                {
                    Rs232.Close();
                    isOpen = false;
                    State_tssl.Text = Port_cob.Text + "端口已关闭";
                    Open_btn.Text = "打开串口";

                    #region 启用控件
                    Port_cob.Enabled = true;
                    Baud_cob.Enabled = true;
                    Parity_cob.Enabled = true;
                    DataBit_cob.Enabled = true;
                    StopBit_cob.Enabled = true;
                    RTS_chb.Enabled = true;
                    DTR_chb.Enabled = true;
                    #endregion
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, "提示");
            }
        }
        #endregion

        #region 单击手动发送按钮事件
        /// <summary>
        /// 单击手动发送按钮事件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Send_btn_Click(object sender, EventArgs e)
        {
            //判断串口是否打开
            if (Rs232.IsOpen)
            {
                //判断发送区是否为空
                if (Send_rxt.Text != "")
                {
                    Console.WriteLine(Transform.ToHexString(sendBuffer.ToArray()));
                    SendData();
                }
                else
                {
                    MessageBox.Show("请先输入数据！！", "提示", MessageBoxButtons.OK, MessageBoxIcon.Warning);
                    Send_rxt.Focus();
                }
            }
            else
            {
                MessageBox.Show("请先打开串口！！", "提示", MessageBoxButtons.OK, MessageBoxIcon.Warning);
            }
        }
        #endregion

        #region 发送数据的方法
        /// <summary>
        /// 发送数据的方法
        /// </summary>
        private void SendData()
        {
            Rs232.Write(sendBuffer.ToArray(), 0, sendBuffer.Count);
            sendCount += sendBuffer.Count;
            SendCount_tssl.Text = sendCount.ToString();
        }
        #endregion

        #region 接收串口发来的数据事件
        /// <summary>
        /// 接收串口发来的数据事件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Rs232_DataReceived(object sender, SerialDataReceivedEventArgs e)
        {
            //判断是否已暂停接收数据
            if (isRxShow == false)
            {
                return;
            }

            byte[] dataTemp = new byte[Rs232.BytesToRead];          //声明读取数据数组长度
            Rs232.Read(dataTemp, 0, dataTemp.Length);               //读取串口数据
            receiveBuffer.AddRange(dataTemp);                       //将串口数据添加到缓存区
            receiveCount += dataTemp.Length;                        //记录数据数量

            //异步
            Invoke(new EventHandler(delegate
            {
                //判断是否是十六进制字符串
                if (!ReceiveHex_chb.Checked)
                {
                    string str = Encoding.GetEncoding("gb2312").GetString(dataTemp);    //将字符数组转换为字符串
                    str = str.Replace("\0", "\\0");                                     //0x00 -> \0结束不会显示

                    Receive_rxt.AppendText(str);                                        //将接收的字符串追加到接收区显示
                }
                else
                {
                    //选中十六状态
                    Receive_rxt.AppendText(Transform.ToHexString(dataTemp, " "));
                }
            }));

            ReceiveCount_tssl.Text = receiveCount.ToString();       //状态栏显示接收数
        }
        #endregion

        #region 单击暂停接收按钮事件
        /// <summary>
        /// 单击暂停接收按钮事件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Pause_btn_Click(object sender, EventArgs e)
        {
            if (isRxShow == true)
            {
                isRxShow = false;
                Pause_btn.Text = "取消暂停";
            }
            else
            {
                isRxShow = true;
                Pause_btn.Text = "暂停接收";
            }
        }
        #endregion

        #region 接收区十六进制复选框事件
        /// <summary>
        /// 接收区十六进制复选框事件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void ReceiveHex_chb_CheckedChanged(object sender, EventArgs e)
        {
            //判断接收区是否为空
            if (Receive_rxt.Text == "")
            {
                return;
            }

            //判断十六进制是否选中
            if (ReceiveHex_chb.Checked == true)
            {
                Receive_rxt.Text = Transform.ToHexString(receiveBuffer.ToArray(), " ");     //当十六进制选择框选中，则将接收的文本转换成十六进制显示
            }
            else
            {
                Receive_rxt.Text = Encoding.GetEncoding("gb2312")
                    .GetString(receiveBuffer.ToArray()).Replace("\0", "\\0");               //当十六进制选择框没有选中，则将接收的文本转取消十六进制显示
            }
        }
        #endregion

        #region 单击手动清空事件
        /// <summary>
        /// 单击手动清空事件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Clear_btn_Click(object sender, EventArgs e)
        {
            receiveBuffer.Clear();                      //清空缓存区
            Receive_rxt.Text = null;                    //清空接收区
            ReceiveCount_tssl.Text = 0.ToString();      //清除接收计数器
        }
        #endregion

        #region 自动清除复选框事件
        /// <summary>
        /// 自动清除复选框事件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void AutoClear_chb_CheckedChanged(object sender, EventArgs e)
        {
            //判断自动清除复选框是否选中
            if (AutoClear_chb.Checked == true)
            {
                Timer.Start();
            }
            else
            {
                Timer.Stop();
            }
        }
        #endregion

        #region 时间变化事件
        /// <summary>
        /// 时间变化事件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Timer_Tick(object sender, EventArgs e)
        {
            if (Receive_rxt.Text.Length >= 4096)
            {
                receiveBuffer.Clear();                      //清空缓存区
                Receive_rxt.Text = null;                    //清空接收区
                ReceiveCount_tssl.Text = 0.ToString();      //清除接收计数器
            }
        }
        #endregion

        #region 当发送区失去焦点事件
        /// <summary>
        /// 当发送区失去焦点事件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Send_rxt_Leave(object sender, EventArgs e)
        {
            if (SendHex_chb.Checked == true)
            {
                if (DataEncoding.IsHexString(Send_rxt.Text.Replace(" ", "")))
                {
                    sendBuffer.Clear();
                    sendBuffer.AddRange(Transform.ToBytes(Send_rxt.Text.Replace(" ", "")));
                }
                else
                {
                    MessageBox.Show("请输入正确的十六进制数据！！", "提示", MessageBoxButtons.OK, MessageBoxIcon.Warning);
                    Send_rxt.Focus();
                }
            }
            else
            {
                sendBuffer.Clear();
                sendBuffer.AddRange(Encoding.GetEncoding("gb2312").GetBytes(Send_rxt.Text));
            }
        } 
        #endregion

        /// <summary>
        /// 发送区文本放生改变事件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Send_rxt_TextChanged(object sender, EventArgs e)
        {

        }

        #region 发送区十六进制复选框事件
        /// <summary>
        /// 发送区十六进制复选框事件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void SendHex_chb_CheckedChanged(object sender, EventArgs e)
        {
            //判断发送区是否为空
            if (Send_rxt.Text == "")
            {
                return;
            }
            //判断是否选中了十六进制
            if (SendHex_chb.Checked == true)
            {
                Send_rxt.Text = Transform.ToHexString(sendBuffer.ToArray(), " ");
            }
            else
            {
                Send_rxt.Text = Encoding.GetEncoding("gb2312").GetString(sendBuffer.ToArray()).Replace("\0", "\\0");
            }
        }
        #endregion

        #region 单击清空发送事件
        /// <summary>
        /// 单击清空发送事件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void ClearSend_btn_Click(object sender, EventArgs e)
        {
            sendBuffer.Clear();                 //清空发送缓存
            Send_rxt.Clear();                   //清空发送区文本
            sendCount = 0;                      //清空发送计数器
            SendCount_tssl.Text = "0";          //清空状态栏发送计数
        } 
        #endregion
    }
}
